package com.zlq.cn.service.un;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zlq.cn.entity.Zuowen;
import com.zlq.cn.mapper.un.ZuowenMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlq.cn.util.StringUtils;
import lombok.SneakyThrows;
import one.util.streamex.StreamEx;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * <p>
 * 作文 服务实现类
 * </p>
 *
 * @author zhoucl
 * @since 2024-04-24
 */
@Service
public class ZuowenService extends ServiceImpl<ZuowenMapper, Zuowen> {

    @Resource
    private ConfigService configService;

    private final Map<String, List<JSONObject>> filterItemMap = new ConcurrentHashMap<>();

    public List<JSONObject> filterItem(Zuowen zuowen) {
        return filterItemMap.computeIfAbsent(zuowen.getCategory(), baseMapper::filterItem);
    }

    @SneakyThrows
    public void pullZuowen() {
        int maxPage = 10;
        Document document = null;
        Elements elements = null;
        String baseUrl = "http://www.zuowen.com/gaozhong/";
        String beginGrade = "高一", beginType = "写人";
        boolean beginGradeFlag = false, beginTypeFlag = false;

        document = Jsoup.connect(baseUrl).get();
        elements = document.select(".taglist li");
        for (Element element : elements) {
            String grade = element.selectFirst("span").text();
            grade = grade.replace("：", "");
            if (beginGrade.equals(grade)) {
                beginGradeFlag = true;
            }
            if (!beginGradeFlag) {
                continue;
            }
            Elements elementsa = element.select("a");
            for (Element elementa : elementsa) {
                String type = elementa.text();
                if (type.contains("全部")) {
                    continue;
                }
                for (int i = 1; i <= maxPage; i++) {
                    String typeUrl = elementa.attr("href");
                    if (i > 1) {
                        typeUrl = typeUrl + String.format("index_%s.shtml", i + "");
                    }
                    Document documentType = Jsoup.connect(typeUrl).get();
                    Elements elementsType = documentType.select(".artlist .artbox_l_t a");
                    List<Zuowen> zuowens = new ArrayList<>();
                    for (Element elementType : elementsType) {
                        String title = elementType.text();
                        Zuowen zuowen = new Zuowen();
                        String newTitle = StringUtils.substringBetween(title, "：", "_");
                        zuowen.setTitle(StringUtils.isBlank(newTitle) ? StringUtils.substringBeforeLast(title, "_") : newTitle);
                        String wordCount = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(title, "_"), "字");
                        zuowen.setWordCount(StringUtils.isBlank(wordCount) ? null : Integer.parseInt(wordCount));
                        String dtlUrl = elementType.attr("href");
                        Document documentDtl = Jsoup.connect(dtlUrl).get();
                        zuowen.setUuid(FilenameUtils.getBaseName(dtlUrl));
                        zuowen.setUrl(dtlUrl);
                        Element elementDate = documentDtl.selectFirst(".composition p");
                        zuowen.setPublishDate(elementDate == null ? LocalDate.now() : LocalDateTimeUtil.parseDate(StringUtils.substring(elementDate.text(), 0, 10), DatePattern.NORM_DATE_FORMATTER));
                        zuowen.setGrade(grade).setType(type);
                        Elements elementsDtl = documentDtl.select(".con_content p:not([style])");
                        String content = StreamEx.of(elementsDtl)
                                .map(Element::text)
                                .filter(StringUtils::isNotBlank)
                                .joining("\r\n");
                        zuowen.setContent(content);
                        if (StringUtils.isNotBlank(zuowen.getTitle()) && StringUtils.isNotBlank(content) && !content.contains("作文网")) {
                            zuowens.add(zuowen);
                        }
                    }
                    saveZuowens(zuowens);
                }
            }
        }
    }

    @SneakyThrows
    public void pullZuowenLngkmf() {
        Document document = Jsoup.parse(FileUtil.readString(new File("C:\\Users\\Administrator\\Desktop\\zuowen.txt"), CharsetUtil.CHARSET_UTF_8));
//        Document document = Jsoup.connect("https://www.zuowen.com/gaokaozw/lngkmf").get();
        Elements elements = document.select(".wrapper.box1");
        for (Element element : elements) {
            String diyu = element.selectFirst("dl dt").text();
            if ("全国卷".equals(diyu)) {
                continue;
            }
            List<Zuowen> zuowens = new ArrayList<>();
            Elements elementsDtls = element.select("li a");
            for (Element elementsDtl : elementsDtls) {
                String dtlUrl = elementsDtl.attr("href");
                try {
                    Document documentDtl = Jsoup.connect(dtlUrl).get();
//                Document documentDtl = Jsoup.parse(FileUtil.readString(new File("C:\\Users\\Administrator\\Desktop\\zuowen_dtl.txt"), CharsetUtil.CHARSET_UTF_8));
                    Zuowen zuowen = new Zuowen();
                    zuowen.setUuid(FilenameUtils.getBaseName(dtlUrl));
                    zuowen.setUrl(dtlUrl);
                    Element elementTitle = documentDtl.selectFirst(".h_title");
                    if (elementTitle == null) {
                        continue;
                    }
                    String title = elementTitle.text();
                    String newTitle = StringUtils.substringBetween(title, "：", "_");
                    if (StringUtils.isBlank(newTitle)) {
                        newTitle = StringUtils.substringAfter(title, "：");
                    }
                    if (StringUtils.isBlank(newTitle)) {
                        newTitle = StringUtils.substringBeforeLast(title, "_");
                    }
                    String year = StringUtils.substring(title, 0, 4);
                    zuowen.setYear(year);
                    zuowen.setRegion(diyu);
                    zuowen.setTitle(newTitle);

                    Element elementDate = documentDtl.selectFirst(".composition p");
                    zuowen.setPublishDate(elementDate == null ? LocalDate.now() : LocalDateTimeUtil.parseDate(StringUtils.substring(elementDate.text(), 0, 10), DatePattern.NORM_DATE_FORMATTER));

                    String wordCount = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(title, "_"), "字");
                    zuowen.setWordCount(StringUtils.isBlank(wordCount) ? null : Integer.parseInt(wordCount));
                    Elements elementsContent = documentDtl.select(".con_content p:not([style])");
                    boolean startContinue = false;
                    StringJoiner content = new StringJoiner("\r\n");
                    for (Element elementContent : elementsContent) {
                        String text = elementContent.text();
                        if (StringUtils.isNotBlank(text)) {
                            if (text.contains("高考作文题目")) {
                                startContinue = true;
                            }
                            if (startContinue) {
                                if (text.contains("高考满分作文")) {
                                    startContinue = false;
                                }
                                continue;
                            }
                            content.add(text);
                        }
                    }
                    zuowen.setContent(content.toString());
                    zuowen.setCategory("2");
                    if (StringUtils.isNotBlank(zuowen.getTitle()) && StringUtils.isNotBlank(zuowen.getContent()) && !zuowen.getContent().contains("作文网")) {
                        zuowens.add(zuowen);
                    }
                } catch (Exception e) {
                    System.out.println(dtlUrl);
                    throw e;
                }
            }
            saveZuowens(zuowens);
        }
    }

    public void saveZuowens(List<Zuowen> zuowens) {
        if (CollectionUtils.isNotEmpty(zuowens)) {
            Set<String> uuids = StreamEx.of(zuowens).map(Zuowen::getUuid).toSet();
            Set<String> extUuids = super.lambdaQuery()
                    .select(Zuowen::getUuid)
                    .in(Zuowen::getUuid, uuids).list().stream()
                    .map(Zuowen::getUuid)
                    .collect(Collectors.toSet());
            StreamEx.of(zuowens)
                    .distinct(Zuowen::getUuid)
                    .filter(zuowen -> !extUuids.contains(zuowen.getUuid()))
                    .toListAndThen(super::saveBatch);
        }
    }

    @SneakyThrows
    public void pullZhongkaotiku() {
        int maxPage = 44;
        String baseUrl = "https://www.zuowen.com/zhongkaozw/zhongkaotiku/";
        for (int i = 11; i <= maxPage; i++) {
            String typeUrl = baseUrl;
            if (i > 1) {
                typeUrl = typeUrl + String.format("index_%s.shtml", i + "");
            }
            System.out.println(typeUrl);
            Document document = Jsoup.connect(typeUrl).get();
            Elements elementsList = document.select(".artlist .artlist_l .artbox_l");
            for (Element element : elementsList) {
                Element elementDtl = element.selectFirst(".artbox_l_t a");
                String text = elementDtl.text();
                if (text.contains("答案") || text.contains("图片版")) {
                    continue;
                }
                Zuowen zuowen = new Zuowen();
                String dtlUrl = elementDtl.attr("href");
                System.out.println(dtlUrl);
                zuowen.setUuid(FilenameUtils.getBaseName(dtlUrl));
                zuowen.setUrl(dtlUrl);
                zuowen.setCategory("3");

                Document documentDtl = Jsoup.connect(dtlUrl).get();
                Element elementTitle = documentDtl.selectFirst(".h_title");
                if (elementTitle == null) {
                    continue;
                }
                String title = elementTitle.text();
                System.out.println(title);
                zuowen.setTitle(title);
                Element elementDate = documentDtl.selectFirst(".composition p");
                zuowen.setPublishDate(elementDate == null ? LocalDate.now() : LocalDateTimeUtil.parseDate(StringUtils.substring(elementDate.text(), 0, 10), DatePattern.NORM_DATE_FORMATTER));

                Element elementDownload = documentDtl.selectFirst(".con_content table a");
                if (elementDownload != null && "本地下载".equals(elementDownload.text())) {
                    String zipUrl = elementDownload.attr("href");
                    try {
                        byte[] zipBytes = HttpUtil.downloadBytes(zipUrl);
                        ZipArchiveInputStream zip = new ZipArchiveInputStream(new ByteArrayInputStream(zipBytes), "GBK");
                        ZipArchiveEntry zipEntry = zip.getNextZipEntry();
                        if (zipEntry != null) {
                            String fileName = zipEntry.getName();
                            String extension = FilenameUtils.getExtension(fileName);
                            ByteArrayOutputStream baos = null;
                            if ("png".equalsIgnoreCase(extension) || "jpg".equalsIgnoreCase(extension)) {
                                List<byte[]> bytes = new ArrayList<>();
                                while (zipEntry != null) {
                                    baos = read(zip);
                                    bytes.add(baos.toByteArray());
                                    zipEntry = zip.getNextZipEntry();
                                }
                                zuowen.setTestQuestionsUrl(putBytePdf(title, bytes));
                            } else {
                                baos = read(zip);
                                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(baos.toByteArray());
                                String name = "zuowen/test_questions/" + fileName;
                                configService.putObject(name, byteArrayInputStream);
                                byteArrayInputStream.close();
                                zuowen.setTestQuestionsUrl(name);
                            }
                            saveZuowens(Collections.singletonList(zuowen));
                        }
                        zip.close();
                    } catch (Exception e) {
                        System.out.println("第几页：" + i);
                    }
                } else {
                    Elements elementsImg = documentDtl.select(".con_content p img");
                    List<String> urls = new ArrayList<>();
                    for (Element elementImg : elementsImg) {
                        String alt = elementImg.attr("alt");
                        if (StringUtils.isNotBlank(alt)) {
                            urls.add(elementImg.attr("src"));
                        }
                    }
                    if (StringUtils.isNotBlank(title) && CollectionUtils.isNotEmpty(urls)) {
                        zuowen.setTestQuestionsUrl(putPdf(title, urls));
                        saveZuowens(Collections.singletonList(zuowen));
                    }
                }
            }
        }
    }

    @SneakyThrows
    private ByteArrayOutputStream read(ZipArchiveInputStream zip) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream outputStream = new BufferedOutputStream(baos);
        byte[] byte_s = new byte[1024];
        int num;
        while ((num = zip.read(byte_s, 0, byte_s.length)) > 0) {
            outputStream.write(byte_s, 0, num);
        }
        outputStream.close();
        return baos;
    }

    @SneakyThrows
    public void gaokaoyuce() {
        FileInputStream fis = new FileInputStream("C:\\Users\\14988\\Desktop\\155258_62eb7ada8eebd.zip");
        String baseUrl = "https://www.zuowen.com/gaokaozw/gaokaoyuce/";
        int maxPage = 125;
        Document document = null;
        Elements elements = null;
        for (int i = 104; i <= maxPage; i++) {
            String typeUrl = baseUrl;
            if (i > 1) {
                typeUrl = typeUrl + String.format("index_%s.shtml", i + "");
            }
            System.out.println(typeUrl);
            Document documentType = Jsoup.connect(typeUrl).get();
            Elements elementsType = documentType.select(".artlist .artbox_l_t a");
            List<Zuowen> zuowens = new ArrayList<>();
            for (Element elementType : elementsType) {
                String title = elementType.text();

                Zuowen zuowen = new Zuowen();
                String year = StringUtils.substring(title, 0, 4);
                try {
                    Integer.parseInt(year);
                    zuowen.setYear(year);
                } catch (Exception e) {

                }
                String newTitle = StringUtils.substringBetween(title, "：", "_");
                zuowen.setTitle(StringUtils.isBlank(newTitle) ? StringUtils.substringBeforeLast(title, "_") : newTitle);
                String wordCount = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(title, "_"), "字");
                zuowen.setWordCount(StringUtils.isBlank(wordCount) ? null : Integer.parseInt(wordCount));
                String dtlUrl = elementType.attr("href");
                Document documentDtl = Jsoup.connect(dtlUrl).get();
                zuowen.setUuid(FilenameUtils.getBaseName(dtlUrl));
                zuowen.setUrl(dtlUrl);
                zuowen.setCategory("4");
                Element elementDate = documentDtl.selectFirst(".composition p");
                zuowen.setPublishDate(elementDate == null ? LocalDate.now() : LocalDateTimeUtil.parseDate(StringUtils.substring(elementDate.text(), 0, 10), DatePattern.NORM_DATE_FORMATTER));
                Elements elementsDtl = documentDtl.select(".con_content p:not([style])");
                String content = StreamEx.of(elementsDtl)
                        .map(Element::text)
                        .filter(StringUtils::isNotBlank)
                        .joining("\r\n");
                zuowen.setContent(content);
                if (StringUtils.isNotBlank(zuowen.getTitle()) && StringUtils.isNotBlank(content) && !content.contains("作文网")) {
                    zuowens.add(zuowen);
                }
            }
            saveZuowens(zuowens);
        }
    }

    @SneakyThrows
    public void zuowenti() {
        FileInputStream fis = new FileInputStream("C:\\Users\\14988\\Desktop\\155258_62eb7ada8eebd.zip");
        String baseUrl = "https://www.zuowen.com/xsczw/zuowenti/";
        int maxPage = 5;
        Document document = null;
        Elements elements = null;
        for (int i = 2; i <= maxPage; i++) {
            String typeUrl = baseUrl;
            if (i > 1) {
                typeUrl = typeUrl + String.format("index_%s.shtml", i + "");
            }
            System.out.println(typeUrl);
            Document documentType = Jsoup.connect(typeUrl).get();
            Elements elementsType = documentType.select(".artlist .artbox_l_t a");
            List<Zuowen> zuowens = new ArrayList<>();
            for (Element elementType : elementsType) {
                String title = elementType.text();

                Zuowen zuowen = new Zuowen();
                String year = StringUtils.substring(title, 0, 4);
                try {
                    Integer.parseInt(year);
                    zuowen.setYear(year);
                } catch (Exception e) {

                }
                String wordCount = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(title, "_"), "字");
                String newTitle = StringUtils.substringBetween(title, "：", "_");
                if (StringUtils.isBlank(newTitle)) {
                    newTitle = StringUtils.substringAfter(title, "：");
                }
                zuowen.setTitle(newTitle);
                try {
                    zuowen.setWordCount(StringUtils.isBlank(wordCount) ? null : Integer.parseInt(wordCount));
                } catch (Exception e) {

                }

                String dtlUrl = elementType.attr("href");
                Document documentDtl = Jsoup.connect(dtlUrl).get();
                zuowen.setUuid(FilenameUtils.getBaseName(dtlUrl));
                zuowen.setUrl(dtlUrl);
                zuowen.setCategory("5");
                Element elementDate = documentDtl.selectFirst(".composition p");
                zuowen.setPublishDate(elementDate == null ? LocalDate.now() : LocalDateTimeUtil.parseDate(StringUtils.substring(elementDate.text(), 0, 10), DatePattern.NORM_DATE_FORMATTER));
                Elements elementsDtl = documentDtl.select(".con_content p:not([style])");
                String content = StreamEx.of(elementsDtl)
                        .map(Element::text)
                        .filter(StringUtils::isNotBlank)
                        .joining("\r\n");
                zuowen.setContent(content);
                if (StringUtils.isNotBlank(zuowen.getTitle()) && StringUtils.isNotBlank(content) && !content.contains("作文网")) {
                    zuowens.add(zuowen);
                }
            }
            saveZuowens(zuowens);
        }
    }

//    @SneakyThrows
    public static void main(String[] args) {
    }

    @SneakyThrows
    private String putPdf(String title, List<String> urls) {
        // 创建一个PDF文档
        PDDocument document = new PDDocument();

        // 循环添加每张图片到PDF
        for (String url : urls) {
            // 加载图片
            System.out.println(title);
            System.out.println(url);
            byte[] bytes = HttpUtil.downloadBytes(url);
            // 创建一个PDF页面
            PDPage page = new PDPage();
            document.addPage(page);
            // 创建图片内容流
            PDPageContentStream contentStream = new PDPageContentStream(document, page);
            // 创建PDImageXObject图片对象
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, bytes, null);
            // 添加图片到页面
            contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth(), pdImage.getHeight());
            contentStream.close();
        }

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 保存PDF文件
        document.save(byteArrayOutputStream);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        String name = "zuowen/test_questions/" + title;
        configService.putObject(name, byteArrayInputStream);
        document.close();
        byteArrayInputStream.close();
        return name;
    }

    @SneakyThrows
    private String putBytePdf(String title, List<byte[]> urls) {
        // 创建一个PDF文档
        PDDocument document = new PDDocument();

        // 循环添加每张图片到PDF
        for (byte[] bytes : urls) {
            // 创建一个PDF页面
            PDPage page = new PDPage();
            document.addPage(page);
            // 创建图片内容流
            PDPageContentStream contentStream = new PDPageContentStream(document, page);
            // 创建PDImageXObject图片对象
            PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, bytes, null);
            // 添加图片到页面
            contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth(), pdImage.getHeight());
            contentStream.close();
        }

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 保存PDF文件
        document.save(byteArrayOutputStream);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        String name = "zuowen/test_questions/" + title + ".pdf";
        configService.putObject(name, byteArrayInputStream);
        document.close();
        byteArrayInputStream.close();
        return name;
    }
}
